/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.mzk.kramerius.articles.importFromLn.articlesData.jiranova;

import cz.mzk.kramerius.articles.importFromLn.PropertyNames;
import cz.mzk.kramerius.articles.importFromLn.articlesData.ArticleComponents;
import cz.mzk.kramerius.articles.importFromLn.articlesData.ArticleComponentsCreator;
import cz.mzk.kramerius.articles.importFromLn.articlesData.ArticleComponentsStatistics;
import cz.mzk.kramerius.articles.importFromLn.articlesData.ArticleStatistics;
import cz.mzk.kramerius.articles.importFromLn.articlesData.ErroneousArticle;
import cz.mzk.kramerius.articles.importFromLn.articlesData.TsvParser;
import cz.mzk.kramerius.articles.importFromLn.domain.Article;
import cz.mzk.kramerius.commons.PropertyLoader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Martin Řehánek (rehan@mzk.cz)
 */
public class JiranovaTsvParser extends TsvParser {

    private static final String EMPTY_STRING = "";
    private static final Logger logger = Logger.getLogger(JiranovaTsvParser.class.getName());
    private static final char FIELD_SEPARATOR = '\t';
    private final List<Article> correctArticles = new ArrayList<Article>();
    private final List<ErroneousArticle> erroneousArticles = new ArrayList<ErroneousArticle>();
    private final List<String> erroneousLines = new ArrayList<String>();
    //TODO: neco udelat s chybnymi radky - tj. ty bez id
    private final ArticleComponentsStatistics acStatistics = new ArticleComponentsStatistics();
    private final ArticleStatistics articleStatistics = new ArticleStatistics();
    private final Requirements requirements;
    private final File inputFile;
    private final File erroneousArticlesFile;
    private Properties properties;

    public JiranovaTsvParser(Properties properties) {
        this.properties = properties;
        requirements = new Requirements(properties);
        PropertyLoader loader = new PropertyLoader(properties);
        inputFile = loader.loadFile(PropertyNames.PARSER_INPUT_FILE, true, true, false);
        erroneousArticlesFile = loader.loadFile(PropertyNames.PARSER_ERR_ARTICLES_FILE, false, false, false);
    }

    @Override
    public List<Article> getCorrectArticles() {
        return correctArticles;
    }

    public List<ErroneousArticle> getErroneousArticles() {
        return erroneousArticles;
    }

    @Override
    public void parseArticles() {
        try {
            LineNumberReader reader = new LineNumberReader(new FileReader(inputFile));
            //List<Article> articles = new ArrayList<Article>();

            int previousId = -1;
            ArticleBuilder articleBuilder = null;
            while (reader.ready()) {
                String line = reader.readLine();
                int lineNumber = reader.getLineNumber();
                if (lineNumber == 1) { //vynechani prvniho radku s hlavickou
                    //logger.log(Level.INFO, "header: {0}", line);
                    continue;
                }

                String[] columns = line.split(String.valueOf(FIELD_SEPARATOR));
                //System.err.println("id: " + columns[0]);

                //article id (not PID)
                String idStr = removeTextDelimits(columns[0]);
                int id = -1;
                try {
                    id = Integer.parseInt(idStr);
                } catch (NumberFormatException e) {
                    logger.log(Level.SEVERE, "No id for line {0}: ''{1}''", new Object[]{lineNumber, idStr});
                    id = -2;
                }

                if (previousId == id) { //clanek pokracuje dalsim rocnikem
                    logger.log(Level.INFO, "Loading volume for previous article, line: {0}, articleId: {1}", new Object[]{lineNumber, id});
                    String[] articleComponentsColumns = Arrays.copyOfRange(columns, 7, line.length());
                    articleBuilder.addArticleComponents(createArticleComponents(id, articleComponentsColumns));
                } else {//novy clanek
                    //logger.log(Level.INFO, "Loading new article, line: {0}, articleId: {1}", new Object[]{lineNumber, id});
                    articleBuilder = createArticleBuilder(columns, id);
                }

                //decide if created article contains errors or not
                articleStatistics.updateCounters(articleBuilder.getErrors());
                if (articleBuilder.hasErrors()) {
                    ErroneousArticleImpl errArticle = new ErroneousArticleImpl();
                    errArticle.setInputData(columns);
                    errArticle.setErrorMessages(articleBuilder.getErrorMessages());
                    erroneousArticles.add(errArticle);
                } else {
                    correctArticles.add(articleBuilder.getArticle());
                }
                previousId = id;
                lineNumber++;
            }
            //printStatistics(statistics);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(JiranovaTsvParser.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(JiranovaTsvParser.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    private ArticleBuilder createArticleBuilder(String[] columns, int articleId) {
        ArticleBuilder articleBuilder = new ArticleBuilder(articleId, requirements);

        articleBuilder.processGenre(arrayElementOrEmptyString(columns, 1));
        articleBuilder.processLanguage(arrayElementOrEmptyString(columns, 2));
        articleBuilder.processAuthor(arrayElementOrEmptyString(columns, 3));
        articleBuilder.processTitle(arrayElementOrEmptyString(columns, 4));
        articleBuilder.procesSubtitle(arrayElementOrEmptyString(columns, 5));
        articleBuilder.procesInfo(arrayElementOrEmptyString(columns, 6));
        //TODO: pouzit note ve foxml
        String noteStr = null;
        if (columns.length >= 13) {
            noteStr = removeTextDelimits(arrayElementOrEmptyString(columns, 12));
        }
        articleBuilder.processNote(noteStr);
        String[] articleComponentsColumns = arrayRange(columns, 7, Math.max(columns.length, 12));
        articleBuilder.addArticleComponents(createArticleComponents(articleId, articleComponentsColumns));
        return articleBuilder;
    }

    private String arrayElementOrEmptyString(String[] array, int position) {
        if (array.length <= position) {
            return EMPTY_STRING;
        } else {
            return array[position];
        }
    }

    private String[] arrayRange(String[] array, int from, int to) {
        String[] result = new String[to - from];
        for (int i = from, j = 0; i < to; i++, j++) {
            if (array.length > i) {
                result[j] = array[i];
            } else {
                result[j] = EMPTY_STRING;
            }
        }
        return result;
    }

    public ArticleComponents createArticleComponents(int id, String[] data) {
        String volume = removeTextDelimits(data[0]);
        String dates = removeTextDelimits(data[1]);
        String issueNumbers = removeTextDelimits(data[2]);
        String dateTimes = removeTextDelimits(data[3]);
        String pages = removeTextDelimits(data[4]);

        ArticleComponentsCreator acc = new SingleVolumeACCreator(properties, volume, dates, issueNumbers, dateTimes, pages, id);
        //statistics
        acStatistics.updateCounters(acc.getError());

        ArticleComponents components = new ArticleComponents();
        components.setComponents(acc.getArticleComponents());
        //components.setErrorMessages(acc.getErrorMessages());
        components.setError(acc.getError());
        return components;
    }

//    public ArticleComponentsStatistics getArticleComponentsStatistics() {
//        return acStatistics;
//    }
    /**
     *
     * @return true if there are some articles present that contain any error
     */
    @Override
    public boolean hasErroneousArticles() {
        return !erroneousArticles.isEmpty();
    }

    @Override
    public void saveErroneousArticles() {
        try {
            FileWriter writer = new FileWriter(erroneousArticlesFile);
            String header = createHeaderLine();
            writer.write(header);
            for (ErroneousArticle article : erroneousArticles) {
                String line = article.toString();//createCsvLine(article);
                writer.write(line);
                writer.write("\n");
            }
            writer.close();
            logger.log(Level.INFO, "Erroneous articles ({0}) saved to file ''{1}''", new Object[]{Integer.valueOf(erroneousArticles.size()), erroneousArticlesFile.getAbsoluteFile()});
        } catch (IOException ex) {
            logger.log(Level.SEVERE, null, ex);
        }
    }

    private String createHeaderLine() {
        StringBuilder builder = new StringBuilder(28);
        builder.append(addTextDelimits("Identifikátor"));
        builder.append(FIELD_SEPARATOR);
        builder.append(addTextDelimits("Žánr"));
        builder.append(FIELD_SEPARATOR);
        builder.append(addTextDelimits("Jazyk (cz/de/jiný)"));
        builder.append(FIELD_SEPARATOR);
        builder.append(addTextDelimits("Autor"));
        builder.append(FIELD_SEPARATOR);
        builder.append(addTextDelimits("Název"));
        builder.append(FIELD_SEPARATOR);
        builder.append(addTextDelimits("Podnázev"));
        builder.append(FIELD_SEPARATOR);
        builder.append(addTextDelimits("[] (Info)"));
        builder.append(FIELD_SEPARATOR);
        builder.append(addTextDelimits("Číslo ročníku"));
        builder.append(FIELD_SEPARATOR);
        builder.append(addTextDelimits("Seznam datumů"));
        builder.append(FIELD_SEPARATOR);
        builder.append(addTextDelimits("Seznam čísel vydání"));
        builder.append(FIELD_SEPARATOR);
        builder.append(addTextDelimits("Seznam druhů vydání (1.ranní/ranní/odpolední/malé)"));
        builder.append(FIELD_SEPARATOR);
        builder.append(addTextDelimits("Seznam stran/intervalů stran"));
        builder.append(FIELD_SEPARATOR);
        builder.append(addTextDelimits("Poznámka"));
        builder.append(FIELD_SEPARATOR);
        builder.append(addTextDelimits("Chybové zprávy"));
        builder.append('\n');
        return builder.toString();
    }

//    public ArticleStatistics getArticleStatistics() {
//        return articleStatistics;
//    }
    @Override
    public void printStatistics(PrintStream out) {
        out.println("Article components statistics: ");
        acStatistics.print(out);

        out.println("Article statistics: ");
        articleStatistics.print(out);
    }
}
